﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace BreukenRekenmachine.Model
{

    struct BreukStruct
    {
        public int teller;
        public int noemer;
    }
    ///    <summary>
    ///     Dit is de Breuk klasse.
    ///     Bevat alle rekenmethodes om met breuken te kunnen werken.
    ///    </summary>
    class Breuk : IComparable<Breuk>
    {
        BreukStruct b;
        private bool geldig = false;

        public bool Geldig
        {
            get { return geldig; }
        }

        private static Random ran = new Random();
        /// <summary>
        /// Constructor om een random breuk aan te maken.
        /// </summary>
        /// <param name="tellerOndergrens">Tellerminimum</param>
        /// <param name="tellerBovengrens">Tellermaximum</param>
        /// <param name="noemerOndergrens">Noemerminimum</param>
        /// <param name="noemerBovengrens">Noemermaximum</param>
        public Breuk(int tellerOndergrens, int tellerBovengrens, int noemerOndergrens, int noemerBovengrens)
        {
            Debug.WriteLine("Breuk Constructor called");
            Teller = ran.Next(tellerOndergrens, tellerBovengrens);
            Noemer = ran.Next(noemerOndergrens, noemerBovengrens);
            Debug.WriteLine("Teller " + b.teller + " Noemer " + b.noemer);
        }
        /// <summary>
        /// Constructor om een specifieke breuk aan te maken.
        /// </summary>
        /// <param name="teller">De teller</param>
        /// <param name="noemer">De noemer</param>
        public Breuk(int teller, int noemer)
        {
            Debug.WriteLine("Breuk Constructor called");
            Teller = teller;
            Noemer = noemer;
            Debug.WriteLine("Teller " + teller + " Noemer " + noemer);
        }
        public Breuk() {  }

        /// <summary>
        /// Vereenvoudigt de breuk.
        /// </summary>
        public void Vereenvoudig()
        {
            Debug.WriteLine("Method Vereenvoudig called");
            int ggd = Hulp.GGD(b.teller, b.noemer);
            b.teller = b.teller / ggd;
            b.noemer = b.noemer / ggd;
            Debug.WriteLine("Nieuwe breuk: " + b.teller + "/" + b.noemer);
        }
        /// <summary>
        /// Deze methode geeft een decimaal getal terug die de breuk moet voorstellen
        /// </summary>
        /// <param name="precisie">Hoeveel cijfers na de komma</param>
        /// <returns>Een string, bestaande uit cijfers die het de breuk moet voorstellen</returns>
        public String Decimaal(int precisie)
        {
            Debug.WriteLine("Method Decimaal called");
            if (precisie < 0) throw new System.ArgumentException("Parameter moet groter zijn dan 0");

            String nullen = new String('0', precisie);
            return String.Format("{0:0." + nullen + "}", (float)b.teller / (float)b.noemer);
        }
        /// <summary>
        /// Methode om breuken te vergelijken.
        /// </summary>
        /// <param name="br">De breuk die vergeleken moet worden met het huidig object</param>
        /// <returns>-1 als de breuk kleiner is, 0 als ze gelijk zijn, 1 als de breuk groter is</returns>
        public int CompareTo(Breuk br)
        {
            Debug.WriteLine("CompareTo called");
            int teller1 = this.Teller * br.Noemer;
            int teller2 = br.Teller * this.Noemer;

            if (teller1 < teller2)
            {
                return -1;
            }
            else if (teller1 == teller2)
            {
                return 0;
            }
            else
            {
                return 1;
            }
        }

        /**
         * Operators
         * **/
         
        public static Breuk operator +(Breuk b1, Breuk b2)
        {
            Debug.WriteLine("Operator Optellen called");
            int kgv = Hulp.KGV(b1.Noemer, b2.Noemer);
            int temp = (b1.Teller * (kgv / b1.Noemer)) + (b2.Teller * (kgv / b2.Noemer));
            Debug.WriteLine("Nieuwe breuk: " + temp + "/" + kgv);
            return new Breuk(temp, kgv);
        }

        public static Breuk operator -(Breuk b1, Breuk b2)
        {
            Debug.WriteLine("Operator Aftrekken called");
            int kgv = Hulp.KGV(b1.Noemer, b2.Noemer);
            int temp = (b1.Teller * (kgv / b1.Noemer)) - (b2.Teller * (kgv / b2.Noemer));
            Debug.WriteLine("Nieuwe breuk: " + temp + "/" + kgv);
            return new Breuk(temp, kgv);
        }

        public static Breuk operator /(Breuk b1, Breuk b2)
        {
            Debug.WriteLine("Operator Delen called");
            int tellerTemp = b1.Teller * b2.Noemer;
            int noemerTemp = b1.Noemer * b2.Teller;
            Debug.WriteLine("Nieuwe breuk: " + tellerTemp + "/" + noemerTemp);
            return new Breuk(tellerTemp, noemerTemp);
        }

        public static Breuk operator *(Breuk b1, Breuk b2)
        {
            Debug.WriteLine("Operator Vermenigvuldigen called");
            int tellerTemp = b1.Teller * b2.Teller;
            int noemerTemp = b1.Noemer * b2.Noemer;
            Debug.WriteLine("Nieuwe breuk: " + tellerTemp + "/" + noemerTemp);
            return new Breuk(tellerTemp, noemerTemp);
        }
        public static Breuk Optellen(Breuk b1,Breuk b2)
        {
            return b1 + b2;
        }

        public static Breuk Aftrekken(Breuk b1, Breuk b2)
        {
            return b1 - b2;
        }

        public static Breuk Vermenigvuldigen(Breuk b1, Breuk b2)
        {
            return b1 * b2;
        }

        public static Breuk Delen(Breuk b1, Breuk b2)
        {
            return b1 / b2;
        }


        public int Teller
        {
            get { return b.teller; }
            set { b.teller = value; }
        }

        public int Noemer
        {
            get { return b.noemer; }
            set
            {
                if (value != 0)
                {
                    b.noemer = value;
                }
                else
                {
                    b.noemer = 1;
                }
                geldig = true;
            }
        }

        public override String ToString()
        {
            Debug.WriteLine("Method ToString klasse Breuk called");
            String voorzetsel = "";
            if (b.teller < 0 || b.noemer < 0) voorzetsel = "-";
            if (b.teller < 0 && b.noemer < 0) voorzetsel = "";

            if (b.noemer == 1) return voorzetsel + Math.Abs(b.teller);
            return voorzetsel + Math.Abs(b.teller) + "/" + Math.Abs(b.noemer);
        }

    }
}
